package org.depsea.oss.config.tenant;

import lombok.extern.slf4j.Slf4j;
import org.depsea.oss.client.OssType;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.lang.NonNull;

import java.util.HashMap;
import java.util.Map;

@Slf4j
public class DefaultTenantOssConfigurationFactory implements TenantOssConfigurationFactory, ApplicationContextAware, DisposableBean, InitializingBean {

    // tenantId - <propName, propValue>
    private final TenantOssConfigProvider configProvider;
    private final Map<String, TenantOssConfiguration> tenantConfigurationMap = new HashMap<>();
    private ApplicationContext applicationContext;

    public DefaultTenantOssConfigurationFactory(TenantOssConfigProvider configProvider) {
        this.configProvider = configProvider;
    }

    public void refresh() throws Exception {
        this.destroy();
        this.tenantConfigurationMap.clear();
        this.initConfig();
    }

    public void initConfig() {
        this.configProvider.forEach((tenantId, config) -> {
            TenantOssConfiguration tenantOssConfiguration = this.createConfiguration(
                    config.getType(), config.getConfig()
            );
            tenantConfigurationMap.put(tenantId, tenantOssConfiguration);
        });
    }

    @Override
    public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    private TenantOssConfiguration createConfiguration(OssType type, Map<String, String> config) {
        if (OssType.ALIYUN == type) {
            return new AliyunTenantOssConfiguration(config, applicationContext);
        } else if (OssType.MINIO == type) {
            return new MinioTenantOssConfiguration(config, applicationContext);
        } else {
            throw new IllegalArgumentException("Unsupported oss type: " + type);
        }
    }

    @Override
    public TenantOssConfiguration getConfiguration(String tenantId) {
        return this.tenantConfigurationMap.get(tenantId);
    }

    @Override
    public void destroy() throws Exception {
        for (TenantOssConfiguration ossConfiguration : tenantConfigurationMap.values()) {
            ossConfiguration.close();
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        this.initConfig();
    }
}
